主要分成四個部份
@use & @import 踩坑先說說新手可能會搞不懂的地方(還是只有我自己XD),Vue 提供開發者透過 lang 屬性宣告語言塊 (如:<style>) 所使用的語言,但實際上,專案內所有樣式的預處理跟打包,是由建構工具來執行的,所以,「要怎麼在 Vue 專案引入 .sass/.scss 檔案」這件事,要看建構工具的官方文件。
這也是 Vue 官方文件在 Pre-Processors 提到的:
Note that integration with various pre-processors may differ by toolchain. Check out the respective documentation for examples:
注意对不同预处理器的集成会根据你所使用的工具链而有所不同,具体细节请查看相应的工具链文档来确认:
- Vite
- Vue CLI
- webpack + vue-loader
我目前專案上使用的建構工具是 Vite,以下說明內容都是以 Vite 為主。
vite 內建支持 .scss、.sass、.less、.styl 和 .stylus 等檔案,沒有 vite 特殊的插件,只要安裝一般的預處理器就可以了。
npm為例)安裝預處理器 Sassnpm add -D sass
<style> 註明使用語言Vue SFC 檔的 language blocks 可以透過 lang 屬性宣告所使用的語言,所以想在 <style> block 使用 SCSS 風格撰寫,必須這樣寫:
<style lang="scss">
$primary-color: #333;
body {
    color: $primary-color;
    }
</style>
好了,就這樣。
(???)
你可能有的疑惑:「我不用自己手動將 .scss 預處理成 .css 嗎?」
對的,不用,交給 vite 處理!
.scss 樣式或變數區域引入指的是:只要將樣式或變數引入到單一元件檔的 <style> 中使用。
我們可以透過 @use 或 @import,將整份 .scss 檔引入到元件檔中,就可以在 <style> 內使用 Sass 變數、@mixin 和 @extend 等。
<style lang="scss" scoped>
@use "@/assets/scss/_font.scss";
@import "@/assets/scss/_colors.scss";
body {
    color: $primary-color;
    font-size: font.$super-big;
    }
</style>
記得在語言塊加上 scoped 屬性,才能將樣式鎖定在區域元件內。(否則就變成全域共享 CSS 樣式啦,還不清楚 scoped 作用的人,建議先去看昨天的文章-Day 14: style scoped 原理)
.scss 樣式想要全域引入 scss 樣式,主要有兩個引入點:
App.vue
main.js
在這裡想要先說明,全域「引入 .scss 樣式」這個說法並不精準,就轉換的執行結果,準確來說是「全域共享這份 .scss 檔所轉換出來的 CSS 樣式」,這也是為什麼要特別區分「樣式」與「Sass 變數」。
App.vue
其實概念和引用到單一元件檔是一樣的,只要不加上 scoped,就可以影響全域的樣式,但因為 App.vue 通常是最整個專案的「根元件」,這裡引入全域樣式是最合理,也更容易管理的。
注意:轉換前的 Sass 變數、@mixin 和 @extend 等等是不能共享的;轉換後的 CSS 樣式,因為沒有 scoped 限制,所以可以影響全域的元件。
<style lang="scss">
@use "@/assets/scss/_font.scss";
@import "@/assets/scss/_colors.scss";
body {
    color: $primary-color;
    font-size: font.$super-big;
    }
</style>
scoped
css 樣式而不是 scss,所以變數、@mixin ** 和** @extend 還是不能全域共享
也就是說,實際上共用的是下面這組樣式:
body {
    color: cyan;
    font-size: 48px;
}
main.js
這個方法一樣是利用轉換後的 CSS 樣式,套用到全域,所以轉換前的 Sass 變數等等還是不能共享。
也就是說,只有 Sass 變數的檔案在這裡引入是沒有意義的,元件檔內也無法使用這些變數。
import { createApp } from "vue";
import App from "./App.vue";
import "./assets/main.css
//只有 Sass 變數的檔案在這裡引用沒有意義
import "@/assets/scss/_colors.scss";
//適合 reset.scss 這類型要套用全局的樣式
import "@/assets/scss/_reset.scss";
const app = createApp(App);
app.mount("#app");
css 樣式而不是 scss,所以變數、@mixin ** 和** @extend 還是不能全域共享
透過 vite 設定來處理,在 vite.config.js 加入下列這段設定:
css: {
  preprocessorOptions: {
    scss: {
      additionalData: `@import "@/assets/global.scss";`
    }
  }
},
@import "@/assets/global.scss"; 這行會被加到每一份 style 中,等同於在每個 SFC <style> 引入 "@/assets/global.scss",如此一來元件就都能取用 global.scss 裡面 scss 的變數!
但在這裡要注意選擇引用的方式(@use v.s @import)。
稍微說明一下 @use 跟 @import 的差異:
@use
fileName.variableName ,避免變數衝突的問題@import
@import
@use
最關鍵的是引入順序,@use 在前,@import 在後,否則會報錯。
css: {
  preprocessorOptions: {
    scss: {
      additionalData: `@use "@/assets/globalColor.scss";`
    }
  }
},
試想,additionalData 的 @import "@/assets/globalColor.scss";這一行字串會寫在檔案的哪裡?
這行字串會被加到每份 <style> 的最前面,所以要注意 @use 跟 @import 的引用順序衝突。
如果選擇在 additionalData 使用:
@import 引入:SFC 內就不能使用 @use 引入 .scss 檔案
只要在任何 SFC 內使用 @use 引入 .scss 檔案,就會直接報錯 (錯誤訊息:@use rules must be written before any other rules.),因為 Sass 的規則就是 @use 在前,@import 在後。
@use 引入注意 name spacing 或改用 * alias
@use 'file':要注意的是,在個別的 SFC 中,雖然看不到引用的檔案名稱,但每次取用變數還是要幫他加上 name spacing!@use 'file' as * 效果如同 @import,可以巧妙避開引用順序報錯,但缺點如 @import,要注意變數衝突的問題。不建議用這個方式引入太多 scss 檔案,因為每份 .scss 檔案都會被所有元件樣式重覆引入。
.scss。main.js 或 App.vue 的 <style> 引入。註:vite 官方文件其實沒有特別提到 additionalData 引入的內容會寫在哪裡,我主要是根據測試報錯內容、vitejs github 討論和 webpack sass loader 說明來推測的。